package de.distmlp.preprocessing.nlp.dictionary;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.StringTokenizer;
import java.util.TreeMap;

public class Dictionary {

	private final String filename;
	private final int minFrequency;
	private Map<String, Integer> dictionary = null;
	private Map<Integer, String> inverseDictionary = null;
	private int maxTerms = 1000;

	public Dictionary(final String filename, final int minFrequency, final int maxTerms) throws IOException {
		this.filename = filename;
		this.minFrequency = minFrequency;
		this.maxTerms = maxTerms;
		this.buildDictionary();
	}

	private void buildDictionary() throws IOException {
		this.dictionary = this.buildDictionary(this.filename, this.minFrequency);
		this.inverseDictionary = Dictionary.buildInverseDictionary(this.dictionary);
	}

	public String getFilename() {
		return this.filename;
	}

	public int getMinFrequency() {
		return this.minFrequency;
	}

	public Map<String, Integer> getDictionary() {
		return this.dictionary;
	}

	public Map<Integer, String> getInverseDictionary() {
		return this.inverseDictionary;
	}

	private static Map<Integer, String> buildInverseDictionary(final Map<String, Integer> dict) {
		final Map<Integer, String> iDict = new TreeMap<Integer, String>();
		for (final Entry<String, Integer> entry : dict.entrySet()) {
			iDict.put(entry.getValue(), entry.getKey());
		}
		return iDict;
	}

	protected class DicItem {
		/**
		 * the tag from the tag cloud
		 */
		public String key;
		/**
		 * how many times was the tag observed
		 */
		private final Integer itemCount;

		public DicItem(final String key, final Integer itemCount) {
			this.key = key;
			this.itemCount = itemCount;
		}
	}

	private Map<String, Integer> buildDictionary(final String filename, final int minFrequency) throws IOException {
		final Map<String, Integer> dic = new HashMap<String, Integer>(300000);
		final File file = new File(filename);
		final BufferedReader reader = new BufferedReader(new FileReader(file));
		String line = null;
		int nbLines = 0;
		try {
			while ((line = reader.readLine()) != null) {
				final StringTokenizer st = new StringTokenizer(line, ",");
				while (st.hasMoreTokens()) {
					final String term = st.nextToken();
					if (dic.containsKey(term)) {
						dic.put(term, dic.get(term) + 1);
					} else {
						dic.put(term, 1);
					}
				}
				nbLines++;
				// System.out.println(nbLines);
			}
		} catch (final IOException e) {
			e.printStackTrace();
		} finally {
			reader.close();
		}
		System.out.println("nbLines(Entities): " + nbLines);
		System.out.println("nbTerms: " + dic.size());
		System.out.flush();

		final List<DicItem> topDicList = new ArrayList<DicItem>(1000);

		for (final Entry<String, Integer> entry : dic.entrySet()) {
			if (entry.getValue() > minFrequency) {
				topDicList.add(new DicItem(entry.getKey(), entry.getValue()));

				// System.out.println("nbTopTerms: " + nbTopTerms);
			}
			// nbTerms++;
			// System.out.println("nbTerms: " + nbTerms + " from " + dicSize );
			// System.out.flush();
		}

		final Comparator<DicItem> comp = new Comparator<DicItem>() {
			@Override
			public int compare(final DicItem dic1, final DicItem dic2) {
				return dic2.itemCount.compareTo(dic1.itemCount);
			}
		};
		java.util.Collections.sort(topDicList, comp);

		final Map<String, Integer> topDic = new HashMap<String, Integer>(1000);

		for (int i = 0; (i < (this.maxTerms)) && (i < (topDicList.size())); i++) {
			final DicItem element = topDicList.get(i);
			topDic.put(element.key, i);
		}
		return topDic;
	}

	public static void writeDictionary(final Dictionary d, final String path) throws IOException {
		final Map<Integer, String> dicMap = d.getInverseDictionary();
		final File f = new File(path + "_dictionary");
		// TODO Support file endings
		if (f.exists()) {
			f.delete();
		}
		f.createNewFile();

		BufferedWriter writer = null;
		try {
			writer = new BufferedWriter(new FileWriter(f));

			for (int i = 0; i < dicMap.size(); i++) {
				writer.append((i) + ":" + dicMap.get(i) + "\n");
			}
		} catch (final IOException e) {
			e.printStackTrace();
		} finally {
			if (writer != null) {
				writer.close();
			}
		}
	}
}
